package com.ayoldi.podcastusbsync.downloader;

import java.io.File;
import java.io.IOException;
import java.net.URL;
import java.util.ArrayList;
import java.util.List;
import java.util.regex.Pattern;

import javax.xml.bind.JAXBException;

import org.apache.commons.io.FileUtils;
import org.apache.log4j.Logger;
import org.joda.time.DateTime;
import org.joda.time.format.DateTimeFormat;
import org.joda.time.format.DateTimeFormatter;

import com.ayoldi.podcastusbsync.configurator.ConfigurationManager;
import com.ayoldi.podcastusbsync.model.Configuration;
import com.ayoldi.podcastusbsync.model.Configuration.UsbDeviceConfiguration.PodcastFeed;
import com.sun.syndication.feed.synd.SyndEnclosure;
import com.sun.syndication.feed.synd.SyndEntry;

public class FeedsDownloaderUtils {

	static Logger LOG = Logger.getLogger(FeedsDownloaderUtils.class);
	
	public static final DateTimeFormatter[] dateFormattersArray = new DateTimeFormatter[] {

		DateTimeFormat.forPattern("dd-MM-yyyy HH:mm:ss"),	
		DateTimeFormat.forPattern("yyyy-MM-dd HH:mm:ss"),
		DateTimeFormat.forPattern("yyyy-MM-dd HH:mm"),
		DateTimeFormat.forPattern("yyyy-MM-dd HH"),
		DateTimeFormat.forPattern("yyyy-MM-dd")

	};
	
	
	public static boolean hasAllowedExtension(String[] allowedExtensions, String url){
		if (url.contains(".")){
			String extension=url.split("\\.")[url.split("\\.").length-1];
			if (extension!=null && extension.length()>0){
				for (String allowedExtension : allowedExtensions){
					if (allowedExtension.equalsIgnoreCase(extension)){
						return true;
					}
				}
			}
			return false;
		}
		return false;
		
		
	}
	
	public static DateTime parseDate(String dateString){
		
		
		if (dateString==null || dateString.trim().length()==0){
			return null;
		}	
		DateTime parsedDate=null;
		for (int i=0;i<dateFormattersArray.length ;i++){
			
			try {
				parsedDate=dateFormattersArray[i].parseDateTime(dateString);
				
			} catch (Exception e) {
				continue;
			}	

			break;
		}
		if (parsedDate!=null){
			LOG.debug("Parsed date "+dateString+" to "+parsedDate.toString());
		}
		else{
			LOG.warn("Could not parse date "+dateString);
		}
		return parsedDate;
	}
	
	public static String formatDate(DateTime dateTime){
		return dateFormattersArray[0].print(dateTime);		
	}


	
	
	public static boolean entryMatchesFeedRegex(String regex, SyndEntry entry){
		return Pattern.matches(regex, entry.getTitle());
	}
	
	public static List<SyndEntry> filterListByFeedRegexp(List<SyndEntry> entries, PodcastFeed feed){
		List<SyndEntry> returnEntries=new ArrayList<SyndEntry>();
		
		if (feed.getRegex()==null || feed.getRegex().length()==0){
			LOG.info("Could not find regex for feed: "+feed.getName());
			returnEntries.addAll(entries);
			return returnEntries;
		}
				
		for (SyndEntry entry : entries){
			if (entryMatchesFeedRegex(feed.getRegex(), entry)){
				LOG.debug("Entry "+ entry.getTitle()+" matched regex "+feed.getRegex());
				returnEntries.add(entry);
			}
			else{
				LOG.debug("Entry "+ entry.getTitle()+" didnt match regex "+feed.getRegex());
			}
		}
		LOG.info("Entries remaining after regex filtering: "+returnEntries.size());
		return returnEntries;
		
		
	}
	
	public static String getFileNameFromTitle(String title, String renameExpr, String filterRegex){
		if (title==null || title.length()==0 || renameExpr==null || renameExpr.length()==0|| filterRegex==null || filterRegex.length()==0){
			return null;
		}
		if (!Pattern.matches(filterRegex, title)){
			return null;
		}
		
		return title.replaceAll(filterRegex, renameExpr);
		
		
	}
	
	public static boolean downloadFile(URL url, File directory, boolean overwriteIfExists, String renamedFileName){
		LOG.info("Downloading file "+url.toString()+" to dir "+directory.getAbsolutePath());
		String fileName=url.getFile().substring(url.getFile().lastIndexOf("/")+1);
		if (renamedFileName!=null && renamedFileName.length()>0){
			String extension=fileName.substring(fileName.lastIndexOf("."));
			fileName=renamedFileName;
			fileName=fileName.
					replace("\\", "-").
					replace("/", "-").
					replace(".", "-").
					replace("<", "-").
					replace(">", "-").
					replace(":", "-").
					replace("\"", "-").
					replace("|", "-").
					replace("?", "-").
					replace("*", "-");
			fileName=fileName+extension;
		}
		
		String finalFilePath=directory.getAbsolutePath()+File.separator+fileName;
		String temporalFilePath=directory.getAbsolutePath()+File.separator+fileName+".part";
		File temporalFile=new File(temporalFilePath);
		File finalFile=new File(finalFilePath);
		boolean fileExists=finalFile.exists();
		if (fileExists){
			LOG.info("File already exists on destination: "+finalFile.getAbsolutePath());
			LOG.info("Overwritting:" +overwriteIfExists);
		}
		
		if (fileExists && !overwriteIfExists){
			return true;
		}
			
		
		try {
			// DELETE TEMPORAL FILE IF EXISTS
			if (temporalFile.exists()){
				temporalFile.delete();
			}
			FileUtils.copyURLToFile(url, temporalFile, 600000, 600000);
		} catch (Exception e) {
			e.printStackTrace();
			LOG.error("Could not download "+url+" to " +finalFile.getAbsolutePath());
			if (temporalFile.exists()){
				temporalFile.delete();
			}
			return false;
		}		
		// DELETE FINAL FILE IF EXISTS
		if (finalFile.exists()){
			finalFile.delete();
		}
		
		
		
		boolean renameSuccess=temporalFile.renameTo(finalFile);
		if (renameSuccess){
			LOG.debug("File succesfully renamed from "+temporalFile.getAbsolutePath()+" to "+finalFile);
			
		}
		else{
			LOG.debug("Could not rename file from "+temporalFile.getAbsolutePath()+" to "+finalFile);

		}
		LOG.info("Succesfully downloaded file to " +finalFile.getAbsolutePath());
		return true;
	}
	
	public static URL getURLToDownloadFromEntry(SyndEntry entry){
		URL downloadURL=null;
		try{
			if (entry.getLink()!=null && FeedsDownloaderUtils.hasAllowedExtension(FeedsDownloaderThread.ALLOWED_EXTENSIONS, entry.getLink())){
				downloadURL=new URL(entry.getLink());
				return downloadURL;
			}
			else if (entry.getUri()!=null && FeedsDownloaderUtils.hasAllowedExtension(FeedsDownloaderThread.ALLOWED_EXTENSIONS, entry.getUri())){
				downloadURL=new URL(entry.getUri());
				return downloadURL;
			}
			else if (entry.getEnclosures()!=null && entry.getEnclosures().size()>0){
				for (Object enclosure : entry.getEnclosures()){
					String enclosureURL=((SyndEnclosure)enclosure).getUrl();
					if (enclosureURL!=null && FeedsDownloaderUtils.hasAllowedExtension(FeedsDownloaderThread.ALLOWED_EXTENSIONS, enclosureURL)){
						downloadURL=new URL(enclosureURL);
						return downloadURL;
					}
				}						
					
			}
		}
		catch(Exception e){
			return null;
		}
		return null;
	}
	
	public static boolean isNewEntry(SyndEntry entry, String checkMode, PodcastFeed feed, ConfigurationManager configManager){
						
		if (checkMode.equals(FeedsDownloaderThread.CHECK_MODE_PUB_DATE)){
			DateTime lastCheckedDate=null;
			lastCheckedDate=FeedsDownloaderUtils.parseDate(feed.getLastChecked());
			DateTime entryDateTime=new DateTime(entry.getPublishedDate());
			if (entryDateTime.isAfter(lastCheckedDate)){
				LOG.info("New entry found after last checked: "+entry.getTitle());
				return true;
			}
			else{
				LOG.info("Entry already crawled (pub date "+FeedsDownloaderUtils.formatDate(entryDateTime)+"): "+entry.getTitle());
			}
			return false;
		}
		else if (checkMode.equals(FeedsDownloaderThread.CHECK_MODE_DOWNLOADS_LOG)){
			DownloadsLog downloadsLog = new DownloadsLog(configManager.getAbsoluteFeedDownloadFolder(feed.getFolder()));
			URL url=FeedsDownloaderUtils.getURLToDownloadFromEntry(entry);
			if (url==null){
				return true;
			}
			if (downloadsLog.containsDownloadedUrl(url.toString())){
				return false;
			}
			else{
				return true;
			}
		}
		else{
			return false;
		}
		
		
	}
	
}
